package com.tao.content.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.tao.base.config.MultipartSupportConfig;
import com.tao.base.dictionary.CourseAuditStatus;
import com.tao.base.exception.LearnHubException;
import com.tao.base.feignClient.MediaClient;
import com.tao.content.domain.dto.CoursePreviewDto;
import com.tao.content.domain.pojo.CoursePublish;
import com.tao.content.domain.pojo.CoursePublishPre;
import com.tao.content.domain.pojo.Teachplan;
import com.tao.content.domain.vo.CourseBaseInfoVo;
import com.tao.content.mapper.CoursePublishMapper;
import com.tao.content.mapper.CoursePublishPreMapper;
import com.tao.content.service.ICoursePublishService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 课程发布 服务实现类
 * </p>
 *
 * @author taohongrun
 * @since 2024-11-01
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class CoursePublishServiceImpl extends ServiceImpl<CoursePublishMapper, CoursePublish> implements ICoursePublishService {

    private final CourseBaseServiceImpl courseBaseService;
    @Autowired
    private  CoursePublishServiceImpl coursePublishServiceSelf;
    private final TeachplanServiceImpl teachplanService;
    private final CoursePublishPreMapper coursePublishPreMapper;
    private final RabbitTemplate rabbitTemplate;
    private final MediaClient mediaClient;

    @Override
    public CoursePreviewDto getCoursePreviewInfo(Long courseId) {

        //课程基本信息、营销信息
        CourseBaseInfoVo courseBaseInfo = courseBaseService.getCourse(courseId);

        //课程计划信息
        List<Teachplan> teachplanTree = Db.lambdaQuery(Teachplan.class).eq(Teachplan::getCourseId, courseId).list();

        CoursePreviewDto coursePreviewDto = new CoursePreviewDto();
        coursePreviewDto.setCourseBase(courseBaseInfo);
        coursePreviewDto.setTeachplans(teachplanTree);
        return coursePreviewDto;
    }

    @Override
    @Transactional
    public void publish(Long companyId, Long courseId) {
        //安全校验
        //注意，此时信息在课程预发布表
        CoursePublishPre coursePublishPre = Db.getById(courseId, CoursePublishPre.class);
        if (coursePublishPre == null)
            LearnHubException.throwMyException("课程为null，不允许发布");
        String status = coursePublishPre.getStatus();
        if (!status.equals(CourseAuditStatus.AUDIT_PASS))
            LearnHubException.throwMyException("课程审核未通过，不允许发布");

        //查询预发布表向课程发布表写入
        CoursePublish coursePublish = new CoursePublish();
        BeanUtils.copyProperties(coursePublishPre, coursePublish);
        coursePublishServiceSelf.save(coursePublish);

        //发送信息
        //添加事务注解，防止发送消息失败导致数据库不一致
        rabbitTemplate.convertAndSend("course_publish_exchange", "course.publish",coursePublish);

        //删除预发布表
        //注意Db依旧为静态工具，无法通过transactional进行回滚
        coursePublishPreMapper.deleteById(companyId);

    }

    //持久层利用freemarker生成html 与 接口层不一样
    private File generateCourseHtml(Long courseId) {
        File htmlFile = null;
        try {
            Configuration configuration = new Configuration(Configuration.VERSION_2_3_32);
            configuration.setIncompatibleImprovements(Configuration.VERSION_2_3_32);
            // 使用ClassPathResource获取模板路径
            ClassPathResource resource = new ClassPathResource("templates/course_template.ftl");
            configuration.setDirectoryForTemplateLoading(resource.getFile().getParentFile());
            configuration.setDefaultEncoding("utf-8");
            Template template = configuration.getTemplate("course_template.ftl");
            CoursePreviewDto coursePreviewInfo = getCoursePreviewInfo(courseId);
            Map<String, Object> map = new HashMap<>();
            map.put("model", coursePreviewInfo);
            String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
            InputStream inputStream = IOUtils.toInputStream(content, StandardCharsets.UTF_8);
            htmlFile = File.createTempFile("course", ".html");
            log.debug("课程静态化，生成静态文件:{}", htmlFile.getAbsolutePath());
            try (FileOutputStream outputStream = new FileOutputStream(htmlFile)) {
                IOUtils.copy(inputStream, outputStream);
            }
        } catch (Exception e) {
            log.error("课程静态化异常:{}", e.toString());
            LearnHubException.throwMyException("课程静态化异常");
        }
        return htmlFile;
    }


    private void uploadCourseHtml(Long courseId, File file)  {
        try {
            MultipartFile multipartFile = MultipartSupportConfig.getMultipartFile(file);
            String course = mediaClient.uploadFiles(multipartFile, "course/"+courseId+".html");
            if(course==null){
                LearnHubException.throwMyException("上传静态文件异常");
                LearnHubException.throwMyException("上传静态文件异常");
            }
        } catch (Exception e){
            log.error("上传静态文件异常:{}",e.toString());
            LearnHubException.throwMyException("上传静态文件异常");
        }

    }

    public void generateAndUploadMinio(Long courseId){
        File file = generateCourseHtml(courseId);
        uploadCourseHtml(courseId,file);
    }


    public CoursePublish getCoursePublish(Long courseId){
        CoursePublish coursePublish = getById(courseId);
        return coursePublish ;
    }

}
